#define GRAPHICSMODULE
#include "GraphicsModule.h"

namespace ModularEngine
{
	BitmapFont::BitmapFont()
	{
		mfTrackingProp = 1;
		mfLeadingProp = 1;
	}

	int BitmapFont::loadFontFull( const char *pFontName, float tracking, float leading )
	{
		string sFontTex = pFontName;
		sFontTex += ".tga";
		string sFontWid = pFontName;
		sFontWid += ".dat";
		loadFont( sFontTex.c_str() );
		loadFontWidths( sFontWid.c_str() );
		mfLeadingProp = leading;
		mfTrackingProp = tracking;
		return 1;
	}

	int BitmapFont::loadFont( const char *pFontPath)
	{
		memcpy( &tFontTexture, GraphicsModule::getSingleton().gI->loadTexture(pFontPath), sizeof(TextureID) );
		return 1;
	}

	int BitmapFont::loadFontWidths( const char *pFontWidthsPath)
	{
		ifstream bFontWidths( pFontWidthsPath, ios::in | ios::binary );
		char temp;

		for( int i = 0; i < 255; i++ )
		{
			bFontWidths.read( (char *)&cWidths[i], sizeof(char) );
			bFontWidths.read( (char *)&temp, sizeof(char) ); 
		}
		bFontWidths.close();
		return 1;
	}

	Vector2d BitmapFont::charPlace(char cWhich)
	{
		Vector2d result  = Vector2d( 0, 0 );
		// 16 characters per line.
		int col = cWhich / 16+1;
		int row = cWhich - col * 16;

		if( row != 0 )
			result.x = (float)row/16;
		if( col != 0 )
			result.y = 1-(float)col/16;

		return result;
	}

	void TextEngine::drawText(ModularEngine::BitmapFont bFont, int height, const char *pText, Vector2d vPos, Vector2d vBounds[2])
	{
		bool bDrawn = false;
		int x = vPos.x;
		int len = strlen( pText );

		float ratio = (float)height/(bFont.tFontTexture.mWidth/16); 
		for( int xCursor = 0; xCursor < len; xCursor++ )
		{
			int charWidth = bFont.charWidth(pText[xCursor]);
			int xPlusW = x+charWidth*ratio;
			if( (x > vBounds[0].x && x < vBounds[1].x ) ||
				(xPlusW > vBounds[0].x && xPlusW < vBounds[1].x) )
			{
				//cout << "drawing" << endl;
				bDrawn = true;
				Vector2d texCoords = bFont.charPlace(pText[xCursor]);

				GraphicsModule::getSingleton().gI->enable( GI_TEXTURE );
				//glEnable( GL_TEXTURE_2D );
				//GraphicsModule::getSingleton().gI->setTexture( bFont.returnTexture() );
				//glBindTexture( GL_TEXTURE_2D, bFont.returnTexture() );
				
				float xTex = texCoords.x+(float)charWidth/bFont.tFontTexture.mWidth;
				Vector2d vTexCoords[2];
				vTexCoords[0] = Vector2d( texCoords.x, texCoords.y );
				vTexCoords[1] = Vector2d( xTex, texCoords.y+.0625 );		
				GraphicsModule::getSingleton().gI->drawQuad( bFont.returnTexture(), vTexCoords, Vector2d( x, vPos.y ), Vector2d( (float)charWidth*ratio, height ) );
#if USING_OLDFORM
				glBegin( GL_QUADS );
					glTexCoord2f( texCoords.x, texCoords.y+.0625  );
					glVertex2f( x, vPos.y );

					
					glTexCoord2f( xTex, texCoords.y+.0625 );
					glVertex2f( xPlusW, vPos.y );

					glTexCoord2f( xTex, texCoords.y );
					glVertex2f( xPlusW, vPos.y+height );

					glTexCoord2f( texCoords.x, texCoords.y );
					glVertex2f( x, vPos.y+height );
				glEnd();
#endif
				


			} else
				if( bDrawn )
					return;

			x+=charWidth*ratio*bFont.mfTrackingProp;
		}
	}

	void TextEngine::drawText( const char *pText, Vector2d vPos )
	{
		drawText( mbDefaultFont, mnDefaultHeight, pText, vPos, mvDefaultBounds );
	}

	void TextEngine::drawText( const char *pText, Vector2d vPos, Vector2d vBounds[2] )
	{
		drawText( mbDefaultFont, mnDefaultHeight, pText, vPos, vBounds );
	}

	void TextEngine::drawTextMultiline( BitmapFont bFont, int height, vector<string> *lines, Vector2d vPos, Vector2d vBounds[2] )
	{
		// While height corresponds to the actual height of each letter and corresponding quad
		// the font leading value will be used to determine the position and visibility of the line.
		bool bDrawn = false;
		int y = vPos.y;
		for( vector<string>::iterator i = lines->begin(); i != lines->end(); i++ )
		{
			int yPlusH = y + height;
			if( (y > vBounds[0].y && y < vBounds[1].y) ||
				(yPlusH > vBounds[0].y && yPlusH < vBounds[1].y ) )
			{
				bDrawn = true;
				drawText( bFont, height, i->c_str(), Vector2d( vPos.x, y ), vBounds );

			} else {
				if( bDrawn )
				{
					return;
				}
			}
			y += height * bFont.mfLeadingProp;
		}

	}

	vector<string> *TextEngine::processMultiline( BitmapFont bFont, int height, const char *pText, int maxWidth )
	{
		vector<string> *words = makeWords( pText );
		vector<string> *lines = new vector<string>;

		int lineWidth = 0;
		string line = "";
		for( vector<string>::iterator i = words->begin(); i != words->end(); i++ )
		{
			int wSize = wordSize( bFont, height, *i );
			if( !strcmp( i->c_str(), "\n" ) )
			{
				// Force Newline
				lines->push_back( line );
				line = "";
				lineWidth = 0;
				continue;
			} else 
			if( wSize > maxWidth )
			{
				THROWERROR( "WCS" );
				// worst case scenario
				// word is bigger than alotted space.
			} else {
				if( wSize + lineWidth < maxWidth )
				{
					line += i->c_str();
					lineWidth += wSize;
				} else {
					lines->push_back( line );
					line = i->c_str();
					lineWidth = 0;
				}
			}
		}

		lines->push_back( line );

		return lines;
	}

	int TextEngine::wordSize(BitmapFont bFont, int nHeight, string sWord)
	{
		int wordSize = 0;
		float ratio = (float)nHeight/(bFont.tFontTexture.mWidth/16);
		for( int i = 0; i < sWord.size(); i++ )
		{
			wordSize += bFont.charWidth( sWord[i] )*ratio;
		}

		return wordSize;
	}

	vector<string> *TextEngine::makeWords( const char *pText )
	{
		vector<string> *words = new vector<string>;
		string tWord = "";
		for( int i = 0; i < strlen( pText ); i++ )
		{
			if( pText[i] == ' ' )
			{
				tWord += " ";
				words->push_back( tWord );
				tWord = "";
				continue;
			} else if( pText[i] == '\n' || pText[i] == '\r' ) 
			{
				if( tWord.size() )
					words->push_back( tWord );
				words->push_back( "\n" );
				tWord = "";
			} else {
				tWord += pText[i];
			}
		}

		words->push_back( tWord );

		return words;
	}

	int GraphicsModule::initialize()
	{
		return 0;
	}

	int GraphicsModule::run()
	{
		return 0;
	}

};